/*
 * This calendar application was forked from Ext Calendar Pro and contributed to
 * Ext JS as an advanced example of what can be built using and customizing Ext
 * components and templates.
 * 
 * If you find this example to be useful you should take a look at the original
 * project, which has more features, more examples and is maintained on a
 * regular basis:
 * 
 * http://ext.ensible.com/products/calendar
 */
Ext.define('Ext.calendar.App', {

	requires : ['Ext.Viewport', 'Ext.layout.container.Border',
			'Ext.picker.Date', 'Ext.calendar.util.Date',
			'Ext.calendar.CalendarPanel',
			'Ext.calendar.data.MemoryCalendarStore',
			'Ext.calendar.data.MemoryEventStore', 'Ext.calendar.data.Events',
			'Ext.calendar.data.Calendars', 'Ext.calendar.form.EventWindow'],

	constructor : function() {
		// Minor workaround for OSX Lion scrollbars
		this.checkScrollOffset();

		// This is an example calendar store that enables event color-coding
		this.calendarStore = Ext.create(
				'Ext.calendar.data.MemoryCalendarStore', {
					data : Ext.calendar.data.Calendars.getData()
				});

		// A sample event store that loads static JSON from a local file.
		// Obviously a real
		// implementation would likely be loading remote data via an HttpProxy,
		// but the
		// underlying store functionality is the same.
		this.eventStore = Ext.create('Ext.calendar.data.MemoryEventStore', {
					data : Ext.calendar.data.Events.getData()
				});

		// This is the app UI layout code. All of the calendar views are
		// subcomponents of
		// CalendarPanel, but the app title bar and sidebar/navigation calendar
		// are separate
		// pieces that are composed in app-specific layout code since they could
		// be omitted
		// or placed elsewhere within the application.
		Ext.create('Ext.Viewport', {
			layout : 'border',
			renderTo : 'calendar-ct',
			padding : '1',
			items : [{
						id : 'app-header',
						region : 'north',
						height : 35,
						border : false,
						contentEl : 'app-header-content'
					}, {
						id : 'app-center',
						title : '...', // will be updated to the current view's
						// date range
						region : 'center',
						layout : 'border',
						listeners : {
							'afterrender' : function() {
								Ext.getCmp('app-center').header
										.addCls('app-center-header');
							}
						},
						items : [{
							id : 'app-west',
							region : 'west',
							width : 179,
							border : false,
							items : [{
								xtype : 'datepicker',
								id : 'app-nav-picker',
								cls : 'ext-cal-nav-picker',
								listeners : {
									'select' : {
										fn : function(dp, dt) {
											Ext.getCmp('app-calendar')
													.setStartDate(dt);
										},
										scope : this
									}
								}
							}]
						}, {
							xtype : 'calendarpanel',
							eventStore : this.eventStore,
							calendarStore : this.calendarStore,
							border : false,
							id : 'app-calendar',
							region : 'center',
							activeItem : 3, // month view

							monthViewCfg : {
								showHeader : true,
								showWeekLinks : true,
								showWeekNumbers : true
							},

							listeners : {
								'eventclick' : {
									fn : function(vw, rec, el) {
										this.showEditWindow(rec, el);
										this.clearMsg();
									},
									scope : this
								},
								'eventover' : function(vw, rec, el) {
									// console.log('Entered evt
									// rec='+rec.data.Title+', view='+ vw.id +',
									// el='+el.id);
								},
								'eventout' : function(vw, rec, el) {
									// console.log('Leaving evt
									// rec='+rec.data.Title+', view='+ vw.id +',
									// el='+el.id);
								},
								'eventadd' : {
									fn : function(cp, rec) {
										this.showMsg('加入 ' + rec.data.Title);
									},
									scope : this
								},
								'eventupdate' : {
									fn : function(cp, rec) {
										this.showMsg('修改 ' + rec.data.Title);
									},
									scope : this
								},
								'eventcancel' : {
									fn : function(cp, rec) {
										// edit canceled
									},
									scope : this
								},
								'viewchange' : {
									fn : function(p, vw, dateInfo) {
										if (this.editWin) {
											this.editWin.hide();
										}
										if (dateInfo) {
											// will be null when switching to
											// the event edit form so ignore
											Ext
													.getCmp('app-nav-picker')
													.setValue(dateInfo.activeDate);
											this.updateTitle(
													dateInfo.viewStart,
													dateInfo.viewEnd);
										}
									},
									scope : this
								},
								'dayclick' : {
									fn : function(vw, dt, ad, el) {
										this.showEditWindow({
													StartDate : dt,
													IsAllDay : ad
												}, el);
										this.clearMsg();
									},
									scope : this
								},
								'rangeselect' : {
									fn : function(win, dates, onComplete) {
										this.showEditWindow(dates);
										this.editWin.on('hide', onComplete,
												this, {
													single : true
												});
										this.clearMsg();
									},
									scope : this
								},
								'eventmove' : {
									fn : function(vw, rec) {
										var mappings = Ext.calendar.data.EventMappings, time = rec.data[mappings.IsAllDay.name]
												? ''
												: ' \\a\\t g:i a';

										var me = this;
										var data = Ext.calendar.data.Events
												.toData(rec.data);
										Request.request('oa-Schedule-save',
												data, function(result) {
													Ext.calendar.data.Events
															.loadDataList(
																	me.eventStore,
																	"name")
												});
										// rec.commit();

										this
												.showMsg('修改 '
														+ rec.data[mappings.Title.name]
														+ ' 移动到 '
														+ Ext.Date
																.format(
																		rec.data[mappings.StartDate.name],
																		('m月d日S' + time)));
									},
									scope : this
								},
								'eventresize' : {
									fn : function(vw, rec) {
										var me = this;
										var data = Ext.calendar.data.Events
												.toData(rec.data);
										Request.request('oa-Schedule-save',
												data, function(result) {
													Ext.calendar.data.Events
															.loadDataList(
																	me.eventStore,
																	"name")
												});
										// rec.commit();
										this.showMsg('修改 ' + rec.data.Title);
									},
									scope : this
								},
								'eventdelete' : {
									fn : function(win, rec) {
										this.eventStore.remove(rec);
										this.showMsg('删除 ' + rec.data.Title);
									},
									scope : this
								},
								'initdrag' : {
									fn : function(vw) {
										if (this.editWin
												&& this.editWin.isVisible()) {
											this.editWin.hide();
										}
									},
									scope : this
								}
							}
						}]
					}]
		});
	},

	// The edit popup window is not part of the CalendarPanel itself -- it is a
	// separate component.
	// This makes it very easy to swap it out with a different type of window or
	// custom view, or omit
	// it altogether. Because of this, it's up to the application code to tie
	// the pieces together.
	// Note that this function is called from various event handlers in the
	// CalendarPanel above.
	showEditWindow : function(rec, animateTarget) {
		if (!this.editWin) {
			this.editWin = Ext.create('Ext.calendar.form.EventWindow', {
						calendarStore : this.calendarStore,
						listeners : {
							'eventadd' : {
								fn : function(win, rec) {
									var me = this;
									var data = Ext.calendar.data.Events
											.toData(rec.data);
									data.id = null;
									Request.request('oa-Schedule-save', data,
											function(result) {
												if (result.success) {
													win.hide();
													rec.data.IsNew = false;

													Ext.calendar.data.Events
															.loadDataList(
																	me.eventStore,
																	"name")

													// me.eventStore.add(rec);
													me.eventStore.sync();
													me.showMsg('添加 '
															+ rec.data.Title);
												}
											});
								},
								scope : this
							},
							'eventupdate' : {
								fn : function(win, rec) {
									var me = this;
									var data = Ext.calendar.data.Events
											.toData(rec.data);
									Request.request('oa-Schedule-save', data,
											function(result) {
												if (result.success) {
													win.hide();
													Ext.calendar.data.Events
															.loadDataList(
																	me.eventStore,
																	"name")
													// rec.commit();
													me.eventStore.sync();
													me.showMsg('修改 '
															+ rec.data.Title);
												}
											});

								},
								scope : this
							},
							'eventdelete' : {
								fn : function(win, rec) {
									var me = this;
									var data = Ext.calendar.data.Events
											.toData(rec.data);

									Request.request('oa-Schedule-deleteByIds',
											{
												ids : data.id
											}, function(result) {
												if (result.success) {
													Ext.calendar.data.Events
															.loadDataList(
																	me.eventStore,
																	"name")
													// me.eventStore.remove(rec);
													me.eventStore.sync();
													win.hide();
													me.showMsg('删除 '
															+ rec.data.Title);
												}
											});
								},
								scope : this
							},
							'eventOk' : {
								fn : function(win, rec) {
									var me = this;
									var data = Ext.calendar.data.Events
											.toData(rec.data);
									Request.request('oa-Schedule-ok',
											{
												id : data.id,
												isOk : data.isOk==1?0:1
											}, function(result) {
												if (result.success) {
													Ext.calendar.data.Events
															.loadDataList(
																	me.eventStore,
																	"name")
													// me.eventStore.remove(rec);
													me.eventStore.sync();
													win.hide();
													me.showMsg('修改 '
															+ rec.data.Title);
												}
											});
								},
								scope : this
							},
							'editdetails' : {
								fn : function(win, rec) {
									win.hide();
									Ext.getCmp('app-calendar')
											.showEditForm(rec);
								}
							}
						}
					});
		}
		this.editWin.show(rec, animateTarget);
	},

	// The CalendarPanel itself supports the standard Panel title config, but
	// that title
	// only spans the calendar views. For a title that spans the entire width of
	// the app
	// we added a title to the layout's outer center region that is
	// app-specific. This code
	// updates that outer title based on the currently-selected view range
	// anytime the view changes.
	updateTitle : function(startDt, endDt) {
		StaticVar_startDate = startDt;
		StaticVar_endDate = endDt;
		Ext.calendar.data.Events.loadDataList(this.eventStore, "name")

		var p = Ext.getCmp('app-center'), fmt = Ext.Date.format;

		if (Ext.Date.clearTime(startDt).getTime() == Ext.Date.clearTime(endDt)
				.getTime()) {
			p.setTitle(fmt(startDt, 'm月d日, Y年'));
		} else if (startDt.getFullYear() == endDt.getFullYear()) {
			if (startDt.getMonth() == endDt.getMonth()) {
				p.setTitle(fmt(startDt, 'm月d日') + '  -  ' + fmt(endDt, 'j, Y'));
			} else {
				p.setTitle(fmt(startDt, 'm月d日') + '  -  '
						+ fmt(endDt, 'm月d日, Y年'));
			}
		} else {
			p.setTitle(fmt(startDt, 'm月d日, Y年') + '  -  '
					+ fmt(endDt, 'm月d日, Y年'));
		}
	},

	// This is an application-specific way to communicate CalendarPanel event
	// messages back to the user.
	// This could be replaced with a function to do "toast" style messages,
	// growl messages, etc. This will
	// vary based on application requirements, which is why it's not baked into
	// the CalendarPanel.
	showMsg : function(msg) {
		Ext.fly('app-msg').update(msg).removeCls('x-hidden');
	},
	clearMsg : function() {
		Ext.fly('app-msg').update('').addCls('x-hidden');
	},

	// OSX Lion introduced dynamic scrollbars that do not take up space in the
	// body. Since certain aspects of the layout are calculated and rely on
	// scrollbar width, we add a special class if needed so that we can apply
	// static style rules rather than recalculate sizes on each resize.
	checkScrollOffset : function() {
		var scrollbarWidth = Ext.getScrollbarSize
				? Ext.getScrollbarSize().width
				: Ext.getScrollBarWidth();

		// We check for less than 3 because the Ext scrollbar measurement gets
		// slightly padded (not sure the reason), so it's never returned as 0.
		if (scrollbarWidth < 3) {
			Ext.getBody().addCls('x-no-scrollbar');
		}
		if (Ext.isWindows) {
			Ext.getBody().addCls('x-win');
		}
	}
}, function() {
	/*
	 * A few Ext overrides needed to work around issues in the calendar
	 */

	Ext.form.Basic.override({
				reset : function() {
					var me = this;
					// This causes field events to be ignored. This is a problem
					// for the
					// DateTimeField since it relies on handling the all-day
					// checkbox state
					// changes to refresh its layout. In general, this batching
					// is really not
					// needed -- it was an artifact of pre-4.0 performance
					// issues and can be removed.
					// me.batchLayouts(function() {
					me.getFields().each(function(f) {
								f.reset();
							});
					// });
					return me;
				}
			});

	// Currently MemoryProxy really only functions for read-only data. Since we
	// want
	// to simulate CRUD transactions we have to at the very least allow them to
	// be
	// marked as completed and successful, otherwise they will never filter back
	// to the
	// UI components correctly.
	Ext.data.MemoryProxy.override({
				updateOperation : function(operation, callback, scope) {
					operation.setCompleted();
					operation.setSuccessful();
					Ext.callback(callback, scope || me, [operation]);
				},
				create : function() {
					this.updateOperation.apply(this, arguments);
				},
				update : function() {
					this.updateOperation.apply(this, arguments);
				},
				destroy : function() {
					this.updateOperation.apply(this, arguments);
				}
			});
});